﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
using System.Timers;
using System.Xml;
using System.IO;

namespace EnergyMonitor
{
    // TODO add new thread for reading data into buffer
    // TODO add new thread for parsing data into queue

    public class Envir : IMonitor
    {
        public delegate void DisplayString(string displayString);

        DisplayString m_displayDelegate;

        private List<string> m_monitorList = new List<string>();

        private Queue<MonitorReading> m_meterReadings = new Queue<MonitorReading>();

        public Queue<MonitorReading> MeterReadings
        {
            get { return m_meterReadings; }
            set { m_meterReadings = value; }
        }

        private SerialPort m_commPort = null;
        private string m_portName;
        private int m_baud;
        private StopBits m_stopBits;
        private Parity m_parity;
        private int m_dataBits;

        private Timer m_pollTimer = new Timer();

        public Envir()
        {
            m_portName = "COM1";
            m_baud = 57600;
            m_stopBits = StopBits.One;
            m_parity = Parity.None;
            m_dataBits = 8;

            // we should really have this off a different thread;
            m_pollTimer.Interval = 1000;
            m_pollTimer.Elapsed += new ElapsedEventHandler(m_pollTimer_Elapsed);

            m_monitorList.Add("Monitor1");
        }

        public void SetDisplay(DisplayString del)
        {
            m_displayDelegate = del;
        }

        void m_pollTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            if (m_commPort.IsOpen)
            {
                try
                {
                    string data = m_commPort.ReadLine();

                    XmlReader reader = XmlReader.Create(new StringReader(data));
                    string time = null;
                    string power = null;

                    reader.Read();
                    if (reader.IsStartElement())
                    {
                        if (reader.Name == "msg")
                        {
                            reader.ReadToDescendant("time");
                            time = reader.ReadString();
                            reader.ReadToNextSibling("ch1");
                            reader.ReadToDescendant("watts");
                            power = reader.ReadString();
                        }
                    }

                    m_meterReadings.Enqueue(new MonitorReading() { ChannelID = "Chan1", MeterID = "Monitor1", Power = power, Time = DateTime.Parse(time).ToString() });

                    m_displayDelegate.Invoke(data);
                }
                catch (TimeoutException)
                {
                }
                catch
                {
                }
            }
            else
            {
                return;
            }
        }

        public List<string> GetMonitorList()
        {
            return m_monitorList;
        }

        public void Start()
        {
            ConfigureCommPort();
            InitialiseCommPort();

            m_pollTimer.Start();
        }

        private void ConfigureCommPort()
        {
        }

        public void SetCommPort(string portName)
        {
            m_portName = portName;

            if (m_commPort != null)
            {
                if (m_commPort.IsOpen)
                {
                    m_commPort.Close();
                }
                InitialiseCommPort();
            }
        }

        private void InitialiseCommPort()
        {
            m_commPort = new SerialPort(m_portName, m_baud, m_parity, m_dataBits, m_stopBits);
            m_commPort.ReadTimeout = 100;
            m_commPort.Open();
        }

        public void ValidateConnection(MonitorInterface deviceInterface)
        {
            if (deviceInterface.InterfaceType != MonitorInterface.Type.Serial)
            {
                throw new InvalidOperationException();
            }

            throw new NotImplementedException();
        }
    }
}
